<?php if (!defined('BASEPATH')) exit('No direct script access allowed');

class Auth extends CPT_Controller{
    
    function __construct(){
        parent::__construct();

        $this->load->helper(array('form',));
        $this->load->library('form_validation');
        $this->load->library('security');
        $this->lang->load('tank_auth');
    }

    /**
     * @TODO The whole message thing is kinda broken, better fix it.
     */
    function index(){
        if ($message = $this->session->flashdata('message')) {
            $this->notification['message'] = $message;
            $this->notification['grade']   = 'warning';
        } else {
            redirect('/auth/login/');
        }
    }

    /**
     * Login user on the site
     *
     * @return void
     */
    function login(){
        $this->headline = 'Member login';
        
        if($this->uri->segment(3)){
            $this->view_data['notification']['message'] = 'Login failed.';
            $this->view_data['notification']['type']    = 'error';
        }
    }
    
    /**
     * Check the login credentials
     *
     * @return void
     */
    function check_login(){
        $redirect_path = 'auth/login/error';

        $this->form_validation->set_rules('username','Username','trim|required|xss-clean');
        $this->form_validation->set_rules('password','Password','trim|required|xss-clean');
        $this->form_validation->set_rules('login','Login','required');

        if($this->form_validation->run()){
            if ($this->tank_auth->login(
                            $this->form_validation->set_value('username'),
                            $this->form_validation->set_value('password'),
                            FALSE,											//remember
                            TRUE,											//Login by Username
                            FALSE)){ 											//Login by E-Mail
                // success
                $redirect_path = 'start';
            }
        }
        redirect($redirect_path);
    }

    /**
     * Logout user
     *
     * @return void
     */
    function logout(){
        $this->tank_auth->logout();

        $this->_show_message($this->lang->line('auth_message_logged_out'));
    }

    /**
     * Register user on the site
     *
     * @return void
     */
    function register(){       
        //user is logged in, so we don't need to show the register page
        if ($this->tank_auth->is_logged_in()) {
            redirect('');
            
        //user is not activated yet
        } elseif ($this->tank_auth->is_logged_in(FALSE)) {
            redirect('/auth/send_again/');
            
        //user registration is not allowed in the config file
        } elseif (!$this->config->item('allow_registration', 'tank_auth')) {
            $this->_show_message($this->lang->line('auth_message_registration_disabled'));
            
        //user is allowed to register
        } else {
            //overwrite the view path since we dont have a register view
            $this->set_content_view('auth/register_form');

            //check if the login happens by using a username
            $use_username = $this->config->item('use_username', 'tank_auth');
            if ($use_username) {
                $this->form_validation->set_rules('username', 'Username', 'trim|required|xss_clean|min_length['.$this->config->item('username_min_length', 'tank_auth').']|max_length['.$this->config->item('username_max_length', 'tank_auth').']|alpha_dash');
            }
            $this->form_validation->set_rules('email', 'Email', 'trim|required|xss_clean|valid_email');
            $this->form_validation->set_rules('password', 'Password', 'trim|required|xss_clean|min_length['.$this->config->item('password_min_length', 'tank_auth').']|max_length['.$this->config->item('password_max_length', 'tank_auth').']|alpha_dash');
            $this->form_validation->set_rules('confirm_password', 'Confirm Password', 'trim|required|xss_clean|matches[password]');

            $captcha_registration	= $this->config->item('captcha_registration', 'tank_auth');
            $use_recaptcha		= $this->config->item('use_recaptcha', 'tank_auth');

            //check if the registration requires captcha verification
            if ($captcha_registration) {
                if ($use_recaptcha) {
                        $this->form_validation->set_rules('recaptcha_response_field', 'Confirmation Code', 'trim|xss_clean|required|callback__check_recaptcha');
                } else {
                        $this->form_validation->set_rules('captcha', 'Confirmation Code', 'trim|xss_clean|required|callback__check_captcha');
                }
            }

            $email_activation = $this->config->item('email_activation', 'tank_auth');

            if ($this->form_validation->run()) {								// validation ok
                if (!is_null($data = $this->tank_auth->create_user(
                                        $use_username ? $this->form_validation->set_value('username') : '',
                                        $this->form_validation->set_value('email'),
                                        $this->form_validation->set_value('password'),
                                        $email_activation))) {									// success

                    $data['site_name'] = $this->config->item('website_name', 'tank_auth');
                    
                    //email activation is enabled
                    if ($email_activation) {									// send "activate" email
                        $data['activation_period'] = $this->config->item('email_activation_expire', 'tank_auth') / 3600;

                        $this->_send_email('activate', $data['email'], $data);

                        unset($data['password']); // Clear password (just for any case)

                        $this->_show_message($this->lang->line('auth_message_registration_completed_1'));
                     
                    //email activation is disabled
                    } else {
                        if ($this->config->item('email_account_details', 'tank_auth')) {	// send "welcome" email
                                $this->_send_email('welcome', $data['email'], $data);
                        }
                        unset($data['password']); // Clear password (just for any case)
                        #$this->_show_message($this->lang->line('auth_message_registration_completed_2').' '.anchor('/auth/login/', 'Login'));
                        $this->view_data['notification']['message'] = 'Registration complete, login ' . anchor('auth/login', 'here') . '.';
                        $this->view_data['notification']['type']    = 'success';
                    }
                //form validation failed!
                } else {
                    $errors = $this->tank_auth->get_error_message();
                    foreach ($errors as $k => $v)	$this->view_data['errors'][$k] = $this->lang->line($v);
                }
            }
            if ($captcha_registration) {
                if ($use_recaptcha) {
                    $this->view_data['recaptcha_html'] = $this->_create_recaptcha();
                } else {
                    $this->view_data['captcha_html'] = $this->_create_captcha();
                }
            }
            $this->view_data['use_username']         = $use_username;
            $this->view_data['captcha_registration'] = $captcha_registration;
            $this->view_data['use_recaptcha']        = $use_recaptcha;
        }
    }

    /**
     * Send activation email again, to the same or new email address
     *
     * @return void
     */
    function send_again(){
        if (!$this->tank_auth->is_logged_in(FALSE)) {							// not logged in or activated
            redirect('/auth/login/');

        } else {
            $this->form_validation->set_rules('email', 'Email', 'trim|required|xss_clean|valid_email');

            $data['errors'] = array();

            if ($this->form_validation->run()) {								// validation ok
                if (!is_null($data = $this->tank_auth->change_email($this->form_validation->set_value('email')))) {			// success
                    $data['site_name']	= $this->config->item('website_name', 'tank_auth');
                    $data['activation_period'] = $this->config->item('email_activation_expire', 'tank_auth') / 3600;

                    $this->_send_email('activate', $data['email'], $data);

                    $this->_show_message(sprintf($this->lang->line('auth_message_activation_email_sent'), $data['email']));

                } else {
                        $errors = $this->tank_auth->get_error_message();
                        foreach ($errors as $k => $v)	$data['errors'][$k] = $this->lang->line($v);
                }
            }
            $this->load->view('auth/send_again_form', $data);
        }
    }

    /**
     * Activate user account.
     * User is verified by user_id and authentication code in the URL.
     * Can be called by clicking on link in mail.
     *
     * @return void
     */
    function activate()
    {
            $user_id		= $this->uri->segment(3);
            $new_email_key	= $this->uri->segment(4);

            // Activate user
            if ($this->tank_auth->activate_user($user_id, $new_email_key)) {		// success
                    $this->tank_auth->logout();
                    $this->_show_message($this->lang->line('auth_message_activation_completed').' '.anchor('/auth/login/', 'Login'));

            } else {																// fail
                    $this->_show_message($this->lang->line('auth_message_activation_failed'));
            }
    }

    /**
     * Generate reset code (to change password) and send it to user
     *
     * @return void
     */
    function forgot_password()
    {
            if ($this->tank_auth->is_logged_in()) {									// logged in
                    redirect('');

            } elseif ($this->tank_auth->is_logged_in(FALSE)) {						// logged in, not activated
                    redirect('/auth/send_again/');

            } else {
                    $this->form_validation->set_rules('login', 'Email or login', 'trim|required|xss_clean');

                    $data['errors'] = array();

                    if ($this->form_validation->run()) {								// validation ok
                            if (!is_null($data = $this->tank_auth->forgot_password(
                                            $this->form_validation->set_value('login')))) {

                                    $data['site_name'] = $this->config->item('website_name', 'tank_auth');

                                    // Send email with password activation link
                                    $this->_send_email('forgot_password', $data['email'], $data);

                                    $this->_show_message($this->lang->line('auth_message_new_password_sent'));

                            } else {
                                    $errors = $this->tank_auth->get_error_message();
                                    foreach ($errors as $k => $v)	$data['errors'][$k] = $this->lang->line($v);
                            }
                    }
                    $this->load->view('auth/forgot_password_form', $data);
            }
    }

    /**
     * Replace user password (forgotten) with a new one (set by user).
     * User is verified by user_id and authentication code in the URL.
     * Can be called by clicking on link in mail.
     *
     * @return void
     */
    function reset_password()
    {
            $user_id		= $this->uri->segment(3);
            $new_pass_key	= $this->uri->segment(4);

            $this->form_validation->set_rules('new_password', 'New Password', 'trim|required|xss_clean|min_length['.$this->config->item('password_min_length', 'tank_auth').']|max_length['.$this->config->item('password_max_length', 'tank_auth').']|alpha_dash');
            $this->form_validation->set_rules('confirm_new_password', 'Confirm new Password', 'trim|required|xss_clean|matches[new_password]');

            $data['errors'] = array();

            if ($this->form_validation->run()) {								// validation ok
                    if (!is_null($data = $this->tank_auth->reset_password(
                                    $user_id, $new_pass_key,
                                    $this->form_validation->set_value('new_password')))) {	// success

                            $data['site_name'] = $this->config->item('website_name', 'tank_auth');

                            // Send email with new password
                            $this->_send_email('reset_password', $data['email'], $data);

                            $this->_show_message($this->lang->line('auth_message_new_password_activated').' '.anchor('/auth/login/', 'Login'));

                    } else {														// fail
                            $this->_show_message($this->lang->line('auth_message_new_password_failed'));
                    }
            } else {
                    // Try to activate user by password key (if not activated yet)
                    if ($this->config->item('email_activation', 'tank_auth')) {
                            $this->tank_auth->activate_user($user_id, $new_pass_key, FALSE);
                    }

                    if (!$this->tank_auth->can_reset_password($user_id, $new_pass_key)) {
                            $this->_show_message($this->lang->line('auth_message_new_password_failed'));
                    }
            }
            $this->load->view('auth/reset_password_form', $data);
    }

    /**
     * Change user password
     *
     * @return void
     */
    function change_password()
    {
            if (!$this->tank_auth->is_logged_in()) {								// not logged in or not activated
                    redirect('/auth/login/');

            } else {
                    $this->form_validation->set_rules('old_password', 'Old Password', 'trim|required|xss_clean');
                    $this->form_validation->set_rules('new_password', 'New Password', 'trim|required|xss_clean|min_length['.$this->config->item('password_min_length', 'tank_auth').']|max_length['.$this->config->item('password_max_length', 'tank_auth').']|alpha_dash');
                    $this->form_validation->set_rules('confirm_new_password', 'Confirm new Password', 'trim|required|xss_clean|matches[new_password]');

                    $data['errors'] = array();

                    if ($this->form_validation->run()) {								// validation ok
                            if ($this->tank_auth->change_password(
                                            $this->form_validation->set_value('old_password'),
                                            $this->form_validation->set_value('new_password'))) {	// success
                                    $this->_show_message($this->lang->line('auth_message_password_changed'));

                            } else {														// fail
                                    $errors = $this->tank_auth->get_error_message();
                                    foreach ($errors as $k => $v)	$data['errors'][$k] = $this->lang->line($v);
                            }
                    }
                    $this->load->view('auth/change_password_form', $data);
            }
    }

    /**
     * Change user email
     *
     * @return void
     */
    function change_email()
    {
            if (!$this->tank_auth->is_logged_in()) {								// not logged in or not activated
                    redirect('/auth/login/');

            } else {
                    $this->form_validation->set_rules('password', 'Password', 'trim|required|xss_clean');
                    $this->form_validation->set_rules('email', 'Email', 'trim|required|xss_clean|valid_email');

                    $data['errors'] = array();

                    if ($this->form_validation->run()) {								// validation ok
                            if (!is_null($data = $this->tank_auth->set_new_email(
                                            $this->form_validation->set_value('email'),
                                            $this->form_validation->set_value('password')))) {			// success

                                    $data['site_name'] = $this->config->item('website_name', 'tank_auth');

                                    // Send email with new email address and its activation link
                                    $this->_send_email('change_email', $data['new_email'], $data);

                                    $this->_show_message(sprintf($this->lang->line('auth_message_new_email_sent'), $data['new_email']));

                            } else {
                                    $errors = $this->tank_auth->get_error_message();
                                    foreach ($errors as $k => $v)	$data['errors'][$k] = $this->lang->line($v);
                            }
                    }
                    $this->load->view('auth/change_email_form', $data);
            }
    }

    /**
     * Replace user email with a new one.
     * User is verified by user_id and authentication code in the URL.
     * Can be called by clicking on link in mail.
     *
     * @return void
     */
    function reset_email()
    {
            $user_id		= $this->uri->segment(3);
            $new_email_key	= $this->uri->segment(4);

            // Reset email
            if ($this->tank_auth->activate_new_email($user_id, $new_email_key)) {	// success
                    $this->tank_auth->logout();
                    $this->_show_message($this->lang->line('auth_message_new_email_activated').' '.anchor('/auth/login/', 'Login'));

            } else {																// fail
                    $this->_show_message($this->lang->line('auth_message_new_email_failed'));
            }
    }

    /**
     * Delete user from the site (only when user is logged in)
     *
     * @return void
     */
    function unregister()
    {
            if (!$this->tank_auth->is_logged_in()) {								// not logged in or not activated
                    redirect('/auth/login/');

            } else {
                    $this->form_validation->set_rules('password', 'Password', 'trim|required|xss_clean');

                    $data['errors'] = array();

                    if ($this->form_validation->run()) {								// validation ok
                            if ($this->tank_auth->delete_user(
                                            $this->form_validation->set_value('password'))) {		// success
                                    $this->_show_message($this->lang->line('auth_message_unregistered'));

                            } else {														// fail
                                    $errors = $this->tank_auth->get_error_message();
                                    foreach ($errors as $k => $v)	$data['errors'][$k] = $this->lang->line($v);
                            }
                    }
                    $this->load->view('auth/unregister_form', $data);
            }
    }

    /**
     * Show info message
     *
     * @param	string
     * @return	void
     */
    function _show_message($message)
    {
            $this->session->set_flashdata('message', $message);
            redirect('/auth/');
    }

    /**
     * Send email message of given type (activate, forgot_password, etc.)
     *
     * @param	string
     * @param	string
     * @param	array
     * @return	void
     */
    function _send_email($type, $email, &$data)
    {
            $this->load->library('email');
            $this->email->from($this->config->item('webmaster_email', 'tank_auth'), $this->config->item('website_name', 'tank_auth'));
            $this->email->reply_to($this->config->item('webmaster_email', 'tank_auth'), $this->config->item('website_name', 'tank_auth'));
            $this->email->to($email);
            $this->email->subject(sprintf($this->lang->line('auth_subject_'.$type), $this->config->item('website_name', 'tank_auth')));
            $this->email->message($this->load->view('email/'.$type.'-html', $data, TRUE));
            $this->email->set_alt_message($this->load->view('email/'.$type.'-txt', $data, TRUE));
            $this->email->send();
    }

    /**
     * Create CAPTCHA image to verify user as a human
     *
     * @return	string
     */
    function _create_captcha()
    {
            $this->load->helper('captcha');

            $cap = create_captcha(array(
                    'img_path'		=> './'.$this->config->item('captcha_path', 'tank_auth'),
                    'img_url'		=> base_url().$this->config->item('captcha_path', 'tank_auth'),
                    'font_path'		=> './'.$this->config->item('captcha_fonts_path', 'tank_auth'),
                    'font_size'		=> $this->config->item('captcha_font_size', 'tank_auth'),
                    'img_width'		=> $this->config->item('captcha_width', 'tank_auth'),
                    'img_height'	=> $this->config->item('captcha_height', 'tank_auth'),
                    'show_grid'		=> $this->config->item('captcha_grid', 'tank_auth'),
                    'expiration'	=> $this->config->item('captcha_expire', 'tank_auth'),
            ));

            // Save captcha params in session
            $this->session->set_flashdata(array(
                            'captcha_word' => $cap['word'],
                            'captcha_time' => $cap['time'],
            ));

            return $cap['image'];
    }

    /**
     * Callback function. Check if CAPTCHA test is passed.
     *
     * @param	string
     * @return	bool
     */
    function _check_captcha($code)
    {
            $time = $this->session->flashdata('captcha_time');
            $word = $this->session->flashdata('captcha_word');

            list($usec, $sec) = explode(" ", microtime());
            $now = ((float)$usec + (float)$sec);

            if ($now - $time > $this->config->item('captcha_expire', 'tank_auth')) {
                    $this->form_validation->set_message('_check_captcha', $this->lang->line('auth_captcha_expired'));
                    return FALSE;

            } elseif (($this->config->item('captcha_case_sensitive', 'tank_auth') AND
                            $code != $word) OR
                            strtolower($code) != strtolower($word)) {
                    $this->form_validation->set_message('_check_captcha', $this->lang->line('auth_incorrect_captcha'));
                    return FALSE;
            }
            return TRUE;
    }

    /**
     * Create reCAPTCHA JS and non-JS HTML to verify user as a human
     *
     * @return	string
     */
    function _create_recaptcha()
    {
            $this->load->helper('recaptcha');

            // Add custom theme so we can get only image
            $options = "<script>var RecaptchaOptions = {theme: 'custom', custom_theme_widget: 'recaptcha_widget'};</script>\n";

            // Get reCAPTCHA JS and non-JS HTML
            $html = recaptcha_get_html($this->config->item('recaptcha_public_key', 'tank_auth'));

            return $options.$html;
    }

    /**
     * Callback function. Check if reCAPTCHA test is passed.
     *
     * @return	bool
     */
    function _check_recaptcha()
    {
            $this->load->helper('recaptcha');

            $resp = recaptcha_check_answer($this->config->item('recaptcha_private_key', 'tank_auth'),
                            $_SERVER['REMOTE_ADDR'],
                            $_POST['recaptcha_challenge_field'],
                            $_POST['recaptcha_response_field']);

            if (!$resp->is_valid) {
                    $this->form_validation->set_message('_check_recaptcha', $this->lang->line('auth_incorrect_captcha'));
                    return FALSE;
            }
            return TRUE;
    }
}

/* End of file auth.php */
/* Location: ./application/controllers/auth.php */